#ifdef MAODV

/*****************************************************************************
 *
 * Copyright (C) 2003 CSHCN, University of Maryland.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * Authors: Dionysus Blazakis <dblaze@umd.edu>
 *          Jonathan Polley <jpolley@umd.edu>
 *          Dan Rusk <drusk@umd.edu>
 *          Manish Karir <karir@umd.edu>
 *          Jonathan McGee <mcgee@umd.edu>
 *
 *****************************************************************************/

#include "maodv_neighbor.h"
#include "routing_table.h"
#include "multicast_routing_table.h"
#include "aodv_rreq.h"
#include "maodv_mact.h"
#include "debug.h"
#include "params.h"

void mcast_neighbor_link_break(rt_table_t *rt){
    mrt_table_t *mrt;
    mrt_nexthop_t *nexthop;
    int i;
    
    /* determine which, if any, groups the broken node is in */
    for(i=0; i<MRT_TABLESIZE; i++){
        mrt=mrt_tbl.tbl[i];

        while(mrt!=NULL){
            nexthop=mrt_nexthop_find(mrt, rt->dest_addr);

            /* only care about activated routes */
            if(nexthop!=NULL && nexthop->activated){
                int nh_dir=nexthop->direction;

                mrt_nexthop_remove(mrt, nexthop->addr);
                if(nh_dir==MRT_UPSTREAM){
                    mrt->is_broken = 1;

                    /* we lost our upstream, find a new one */
                    rreq_route_discovery(mrt->grp_addr, 
                        RREQ_JOIN|RREQ_GRP_REBUILD, NULL, 0);
                }else{
                    /* we lost our downstream, wait to see if he returns */
                    mrt_nexthop_remove(mrt, nexthop->addr);

                    if(!mrt->is_member && mrt->activated_downstream_cnt==0){
                        DEBUG(LOG_DEBUG, 0, "setting prune dangle timer");

                        /* set timeout to prune self if downstream doesn't
                         * reconnect */
                        mrt->prune_timer.handler = (timeout_func_t) &mcast_prune_dangle;
                        mrt->prune_timer.data = &mrt;

                        /* 20 seconds of rebuild time. */
                        timer_set_timeout( &mrt->prune_timer, PRUNE_TIMEOUT );
                    }
                }
            }else if(nexthop!=NULL && !nexthop->activated){
                mrt_nexthop_remove(mrt, nexthop->addr);
            }
            
            mrt=mrt->next;
        }
    }
}

/* mcast_prune_dangle
 * if you become a router only with no downstream nodes, (dangling) then
 * prune self after a timeout */
void mcast_prune_dangle( mrt_table_t *mrt ) {
    mrt_nexthop_t * upstream;

    DEBUG(LOG_DEBUG, 0, "in prune dangle timer");
    if ( mrt->activated_downstream_cnt == 0 && !mrt->is_member 
            && (!mrt->is_gateway || (mrt->activated_upstream_cnt == 0))) {
        /* prune me */

        upstream = mrt_table_get_activated_upstream( mrt ); 
        DEBUG( LOG_DEBUG, 0, "Pruning myself after a reasonable timeout." );

        if(upstream != NULL){
            mact_send( MACT_PRUNE, 1, mrt->grp_addr, upstream->addr, 1 );
            mrt_nexthop_deactivate( mrt, upstream->addr );
        }

        mrt_table_stop_routing(mrt);
    }
}

#endif
